import { useEffect, useRef } from 'react';
import path from 'path';

export default function useServiceLoader(apps, statusHandler) {
  const serviceListRef = useRef([]);
  const loadedServices = useRef({});

  useEffect(() => {
    serviceListRef.current = apps;
  }, [apps]);

  const __createElements = (url, service, ele) => {
    return new Promise(() => {
      const element = document.createElement(ele.name);
      Object.keys(ele.options).forEach((key) => {
        element[key] = ele.options[key];
      });

      element.onerror = () => {
        statusHandler({ status: 'failed', msg: `${service.name} resource load failed` });
      }
      document[ele.position].appendChild(element);
    });
  };

  const __loadResource = (url, service) => {
    if(/\.css/.test(url)) {
      return __createElements(
        url, service, { name: 'link', options: { rel: 'stylesheet', href: url }, position: 'head' }
      );
    }

    return __createElements(
      url, service, { name: 'script', options: { type: 'module', async: true, src: url }, position: 'body' }
    );
  };

  const __getResources = ({ service, uri, ...resources }) => {
    const loader = _.map(resources, (res) => {
      const url = path.join(uri, process.env.SUB_MODULE_OUTPUT, res);
      __loadResource(url, service).then(() => {
        return null;
      }).catch(err => (console.log('err', err)));
    });
    if (loader.length > 0) {
      return Promise.all(loader).then(() => {
        loadedServices.current[service.name] = service;
        return null;
      }).catch(err => ({ status: 'failed', err }));
    }
  };

  const __onloadService = (config) => {
    const { title, contextRoot } = config;
    const uri = path.join('/', contextRoot);
    const serviceUrl = path.join(uri, process.env.SUB_MODULE_OUTPUT, `config.micro?v=${Date.now()}`);

    return fetch(serviceUrl, {
      method: 'GET'
    }).then(res => res.json()).then((serviceCfg) => {
      return __getResources({ service: config, uri, ...serviceCfg });
    }).catch(() => {
      return { status: 'failed', msg: `Load ${title} resources failed.`}
    });
  };

  const loadService = (name) => {
    const app = serviceListRef.current.find(s => name === s.module);
    if (!app) {
      return { status: 'error' };
    }

    if (loadedServices.current[app.module]) return { status: 'processing' };

    return __onloadService(app);
  };

  return [loadService];
}
